from django.shortcuts import render,HttpResponse,redirect
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from collects.views import check_login
from datetime import datetime
import redis
from django.db import transaction
from django.conf import settings
from alipay import AliPay
import os
from django.core.paginator import Paginator


# Create your views here.

# 准备秘钥的工具
app_private_path = os.path.join(settings.BASE_DIR,'keys/app_side.txt')
alipay_public_key_path = os.path.join(settings.BASE_DIR,'keys/alk_gong.txt')

# 读取秘钥的内容
app_private_key_string = open(app_private_path,'r').read()
alipay_public_key_string = open(alipay_public_key_path,'r').read()


# 定义自己的支付类
class MyAlipay(APIView):
    def __init__(self,*args,**kwargs):
        # 继承父类中的__init__
        super().__init__(*args,**kwargs)
        # 初始化一个自己的实例属性
        self.alipay = AliPay(
            # 沙箱id
            appid = '2021000121639206',
            # 私钥
            app_private_key_string = app_private_key_string,
            # 支付宝公钥
            alipay_public_key_string = alipay_public_key_string,
            app_notify_url=None,  # 回调地址
            # 签名算法
            sign_type = 'RSA2',
            debug = True,  # 支付宝就会发送到支付宝沙箱环境

        )
    # 生成支付地址的方法
    # order_id 订单编号，total_amount：总价格
    def get_trade_url(self,order_id,total_amount):
        # 生成支付订单的相关参数
        order_string = self.alipay.api_alipay_trade_page_pay(
            subject='商家收款',
            out_trade_no=order_id,
            total_amount=total_amount,
            # 前端服务器get请求地址
            return_url='http://localhost:8000/pay/result/', # 支付回调的地址
            # 沙箱服务器post请求地址
            notify_url='http://localhost:8000/pay/result/',
        )

        # 返回一个支付地址
        return 'https://openapi.alipaydev.com/gateway.do?' + order_string




# 创建订单的视图
class Orderr(MyAlipay):
    # 创建订单
    @check_login
    def post(self,request):
        # 1.接受前端数据

        # 商品字典列表
        goods_list = request.data.get('products')
        # 商品id
        addr_id = request.data.get('addr')
        # 支付模式
        pay_method = request.data.get('payMethod')

        print('接受的结算前端数据',goods_list,'xiao',addr_id,'dada',pay_method)
        # 2.获取用户信息 request.user 或者 request.uid
        user = request.user
        print('接受的用户信息',user)
        # 3.准备订单的相关数据，插入订单表
        # strftime 将日期类格式化为字符串
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + '_%s'%user.id
        try:
            addr = UserAddr.objects.get(id=addr_id)
        except:
            return Response({
                'code':400,
                'msg':'请添加收货地址'
            })
        # 数量
        total_count = 0
        # 总价
        total_amount = 0

        # 显示开启一个事物
        with transaction.atomic():
            # 事物的回滚点
            point = transaction.savepoint()

            try:
                # 插入订单数据-->到订单表
                # 在订单里添加数据

                order = Order.objects.create(order_id=order_id,user=user,address=addr,total_count=total_count,total_amount=total_amount,pay_method=int(pay_method))


                # 4.创建订单商品数据，并插入订单商品表（注意判断库存是否足够）
                for good in goods_list:
                    print('每一个需要购买的商品',good,type(good))
                    # 采用乐观锁  标志循环判断的次数
                    t = 0
                    while t < 3:
                        # 商品对象
                        good_obj = Goods.objects.filter(id=good.get('productID')).first()
                    # 如果对象不存在，就反回noll
                        if not good_obj:
                            msg = '商品不存在'
                            # 引发一个异常，被外层的try捕获
                            raise ValueError(msg)

                        # 获取原始的库存和销量
                        # 库存
                        origin_stock = good_obj.stock
                        # 销量
                        origin_count = good_obj.count

                        # 判断当前商品的购买数量，与库存数量的大小关系
                        if good.get('num') > origin_stock:
                            msg = '商品库存不足，不发购买'
                            raise ValueError(msg)

                            # 库存充足，可以正常购买   订单商品表里面添加商品
                            # 需要判断当前库存销量是否与原有的销量库存一致

                        result = Goods.objects.filter(id=good.get('productID'),stock=origin_stock,count=origin_count)
                        if not result:
                            # 说明其他事物更新了其他商品库存的销量
                            # 此次更新失败，进入下次循环
                            t += 1
                            continue
                            # 若销量库存前后一致则结束循环判断
                        break
                    else:
                        msg = '创建订单冲突'
                        raise ValueError(msg)
                        # 插入订单商品数据
                    OrderGood.objects.create(good=good_obj,count=good.get('num'),price=good.get('price'),order=order)
                    # 5.更新库存商品销量，销量响应的增加
                    # 减库存
                    good_obj.stock = origin_stock - good.get('num')
                    # 加销量
                    good_obj.count = origin_count + good.get('num')
                    # 保存
                    good_obj.save()


                    # 处理订单中的商品数量、价格
                    # 计算所有剩下的数量
                    total_count += good.get('num')
                    # 价格
                    total_amount += good.get('num') * good.get('price')
                # 更新订单的总商品数，总价格
                order.total_count = total_count
                order.total_amount = total_amount
                order.save()
            except Exception as e:
                print('失败原因',e)
                # 创建订单失败回滚事物
                transaction.savepoint_rollback(point)
                return Response({
                    'code':400,
                    'msg':'失败',
                })
            # 订单成功，提缴事物
            transaction.savepoint_commit(point)
        # 6.订单完成后需要删除购物车中已经购买的商品
        redis_conn = redis.Redis(host='localhost',port=6379,db=1,password='123321')
        # 构造key
        cart_key = 'cart_%s'%user.id
        cart_selected_key = 'cart_selected_%s'%user.id
        # 获取循环字典，并逐一删除
        for i in goods_list:
            redis_conn.hdel(cart_key,i.get('productID'))
            redis_conn.srem(cart_selected_key,i.get('productID'))

        # 7.返回响应
        # 生成一个支付地址
        pay_url = self.get_trade_url(order_id,total_amount)

        return Response({
            'code':201,
            'msg':'创建订单成功',
            'pay_url':pay_url
        })

# 加载用户的订单
    @check_login
    def get(self,request):
        # 接受前端的数据
        pageSize = request.query_params.get('pageSize')
        currentPage = request.query_params.get('currentPage')

        print('大打发第三方',pageSize,currentPage)

        # 混去用户信息
        user = request.user

        # 当前用户对象  根据用户对象，获取期所有的订单
        orders = Order.objects.filter(user=user)

        wang = Paginator(orders,pageSize)

        page = wang.page(currentPage)


        # 便利所有订单。查询每一个订单中的订单商品，组织orders的json数据结构
        orders_list = []
        for order in page:
            order_goods = order.ordergood_set.all()
            order_good_list = []
            for order_good in order_goods:
                good_dict = {
                    'productID':order_good.good.id,
                    'productName':order_good.good.sku_name,
                    'productImg':order_good.good.img,
                    'productPrice':order_good.price,
                    'productNum':order_good.count,
                    'orderID':order.order_id,
                    'createdTime':order.created_time,
                    'payStatus':order.get_pay_status_display()

                }
                order_good_list.append(good_dict)
            orders_list.append(order_good_list)
        print('数量',orders.count())
        # 返回响应
        return Response({
            'code':200,
            'msg':'加载订单成功',
            'orders':orders_list,
            'total1':orders.count()
        })


    def put(self,request):
        # 接受前端数据
        label = request.data.get('label')
        order_id = request.data.get('orderID')
        total_amount = request.data.get('totalAmount')
        print('接受的前端数据',label,order_id,total_amount)

        # 根据ledel的值，执行不同的代码
        # label == '待支付',生成支付地址，返回响应
        if label == '待支付':
            pay_url = self.get_trade_url(order_id,total_amount)

            return Response({
                'code':200,
                'msg':'支付成功',
                'pay_url':pay_url
            })

        elif label == '待收货':
            # 要确认收货的地址，即更新订单的状态为待评价
            order = Order.objects.filter(order_id=order_id).first()

            order.pay_status += 1
            order.save()

            return Response({
                'code':200,
                'msg':'发货成功'
            })

        return Response({
            'code':500,
            'msg':'后端逻辑待实现'
        })

    def delete(self,request):
        # 接受前端数据
        order_id = request.data.get('orderID')
        good_id = request.data.get('productID')

        print('接受的前端id',order_id,good_id)

        # 查询订单对象，订单商品对象，需要判断，进行删除
        # 如果订单中只有一个商品，连同订单一起删除
        # 否则订单有多个订单商品，只删除订单中制定的订单商品
        order = Order.objects.filter(order_id=order_id).first()


        # 反向查询
        goods_query_set = order.ordergood_set.all()
        if goods_query_set.count() == 1:
            # 商品和订单一起删除
            order.delete()
        elif goods_query_set.count() >1 :
            # 只删除一个商品
            for i in goods_query_set:
                if i.good.id == good_id :
                    i.delete()

        return Response({
            'code':200,
            'msg':'删除订单的商品成功'
        })



class Wang(APIView):
    def get(self,request,pk):
        ordd = Order.objects.filter(pay_status=pk)

        dada = []
        for i in ordd:
            topm = {
                'order_id':i.order_id,
                'total_count':i.total_count,
                'total_amount':i.total_amount,
                'freight':i.freight,
                'pay_method':i.pay_method,
                'pay_status':i.pay_status,
                'created_time':i.created_time,
                'updated_time':i.updated_time,
            }
            dada.append(topm)

        return Response({
            'code':200,
            'msg':'成功',
            'data':dada
        })



# 查看支付结果路由
class Chendamama(MyAlipay):
    # 接受前端浏览器的get请求(request.url)
    def get(self,request):
        print('查看查询参数',request.query_params)
        # 获取交易编号
        order_id = request.query_params.get('out_trade_no')

        # 查询当前订单的支付结果
        pay_result = self.alipay.api_alipay_trade_query(order_id)
        print('支付结果',pay_result)
        # 查询订单对象
        order = Order.objects.filter(order_id=order_id).first()
        if pay_result.get('trade_status') == 'TRADE_SUCCESS':
            # 支付成功
            pay_status = 1

            # 删除购物车中已购买的商品
            redis_conn = redis.Redis(host='localhost',port=6379,db=1,password='123321')
            # 查询所有的订单商品
            goods = order.ordergood_set.all()
            cart_key = 'cart_%s'%order.user.id
            cart_selected_key = 'cart_selected_%s'%order.user.id
            for i in goods:
                redis_conn.hdel(cart_key,i.good.id)
                redis_conn.srem(cart_selected_key,i.good.id)
            # 关闭redis
            redis_conn.close()

            # 更新订单的状态
            order.pay_status += 1
            order.save()


            # 支付成功，让用户回到订单页面
            return  redirect('http://localhost:8080/#/order/')

        else:
            # 支付失败
            pay_status = 0


        return Response({
            'code':200,
            'msg':'支付成功' if pay_status else '支付失败'
        })

    # 接受支付宝沙箱的post请求(notify_url)

    def post(self,request):
        # 获取数据
        data_dict = {k:v for k , v in request.data.itms()}
        # 验证当前的post请求是否是支付宝发过来的
        sign = data_dict.pop('sign')
        # 验证结果
        validate_result = self.alipay.verify(data_dict,sign)

        if validate_result:
            # 说明是支付宝发来的请求
            if data_dict.get('trade_status') == 'TRADE_SUCCESS':
                # 支付成功
                return HttpResponse('success')
        else:
            # 说明不是支付宝发来的请求
            return Response({
                'code':400,
                'msg':'非法的请求'
            })





